package com.jiangxjsy.gateway.exception;

import com.alibaba.fastjson.JSON;
import com.jiangxjsy.core.exception.BasicException;
import com.jiangxjsy.core.exception.FeignServiceException;
import com.jiangxjsy.core.exception.NoLoginException;
import com.jiangxjsy.core.wrap.Result;
import com.jiangxjsy.core.wrap.ResultBuilder;
import com.jiangxjsy.core.wrap.ResultCode;
import com.jiangxjsy.model.core.entity.UserExtra;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Mono;

import java.util.Map;

/**
 * wukong-crm-master
 * 蒋胜宇
 * 2025/5/31 18:06
 */

@Component
@Order(-2)
@Slf4j
public class WebExceptionHandler extends AbstractErrorWebExceptionHandler {
    public WebExceptionHandler(ErrorAttributes errorAttributes,
                               ApplicationContext applicationContext,
                               ServerCodecConfigurer serverCodecConfigurer
    ) {
        super(errorAttributes, new ResourceProperties(), applicationContext);
        super.setMessageWriters(serverCodecConfigurer.getWriters());
        super.setMessageReaders(serverCodecConfigurer.getReaders());
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    private Mono<ServerResponse> renderErrorResponse(final ServerRequest request) {
        Throwable error = getError(request);
        Map<String, Object> errorAttributes = this.getErrorAttributes(request, false);
        BodyInserter<Result<?>, ReactiveHttpOutputMessage> result;
        log.error("Gateway request error: {}", JSON.toJSONString(errorAttributes));

        if (error instanceof BasicException) {
            result = BodyInserters.fromValue(ResultBuilder.error((BasicException) error));
            return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(result);

        } else if (error instanceof FeignServiceException) {
            FeignServiceException feignError = (FeignServiceException) error;
            result = BodyInserters.fromValue(ResultBuilder.error(feignError.status(), feignError.getMessage()));
            return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(result);

        } else if (error instanceof NoLoginException) {
            Result<UserExtra> resultData = ResultBuilder.error(ResultCode.SystemResultCode.SYSTEM_NOT_LOGIN);
            resultData.setData((UserExtra) ((NoLoginException) error).getUserExtra());
            result = BodyInserters.fromValue(resultData);
            return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(result);

        } else {
            Integer status = (Integer) errorAttributes.get("status");
            result = BodyInserters.fromValue(ResultBuilder.error(ResultCode.parse(status, ResultCode.SystemResultCode.class)));
            return ServerResponse.status(HttpStatus.valueOf(status)).contentType(MediaType.APPLICATION_JSON).body(result);
        }
    }
}
